using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using OurWedding1.Models;

namespace OurWedding1.Controllers
{
    [Authorize]
    public class ExpensesController : BaseController
    {
        private readonly IContractorRepository _contractorRepository;
        private readonly IExpenseCategoryRepository _expensecategoryRepository;
        private readonly IExpenseRepository _expenseRepository;
        private readonly IGuestRepository _guestRepository;
        private readonly IExpenseTypeRepository _expenseTypeRepository;

        // If you are using Dependency Injection, you can delete the following constructor
        public ExpensesController()
            : this(new ExpenseTypeRepository(), new GuestRepository(), new ContractorRepository(), new ExpenseCategoryRepository(), new ExpenseRepository())
        {
        }

        public ExpensesController(IExpenseTypeRepository expenseTypeRepository,IGuestRepository guestRepository,  IContractorRepository contractorRepository, IExpenseCategoryRepository expensecategoryRepository, IExpenseRepository expenseRepository)
        {
            _contractorRepository = contractorRepository;
            _expensecategoryRepository = expensecategoryRepository;
            _expenseRepository = expenseRepository;
            _guestRepository = guestRepository;
            _expenseTypeRepository = expenseTypeRepository;
        }

        //
        // GET: /Expenses/

        public ActionResult Index()
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            var entities = _expenseRepository.AllIncluding(expense => expense.Wedding, expense => expense.Contractor, expense => expense.ExpenseCategory, expense => expense.Tasks, expense => expense.Installments);
            entities = entities.Where(e => e.WeddingId == selectedWedding);
            return View(entities);
        }

        public ActionResult IndexAjax()
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            var entities = _expenseRepository.AllIncluding(expense => expense.Wedding, expense => expense.Contractor, expense => expense.ExpenseCategory, expense => expense.Tasks, expense => expense.Installments);
            entities = entities.Where(e => e.WeddingId == selectedWedding).OrderBy(d => d.ExpenseCategoryId);
            var model = entities.ToList();
            var guests = _guestRepository.All.Where(g => g.GuestGroup.WeddingId == selectedWedding.Value).Where(g => !g.isNotIncluded);
            var guestsNmb = guests.Count();
            var guestHotelNmb = guests.Count(d => d.isHotelNeeded);
            model = ComputeAmounts(guestsNmb, guestHotelNmb, model);
            return PartialView("_Index", model);
        }



        public JsonResult GetPieChartData()
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return Json(null);
            }

            var entities = _expenseRepository.AllIncluding(expense => expense.Wedding, expense => expense.Contractor, expense => expense.ExpenseCategory, expense => expense.Tasks, expense => expense.Installments);
            entities = entities.Where(e => e.WeddingId == selectedWedding.Value).Where(e=>!e.isNotIncluded).OrderBy(d => d.ExpenseCategoryId);
            List<Expense> model = entities.ToList();
            var guests = _guestRepository.All.Where(g => g.GuestGroup.WeddingId == selectedWedding.Value).Where(g => !g.isNotIncluded);
            var guestsNmb = guests.Count();
            var guestHotelNmb = guests.Count(d => d.isHotelNeeded);
            model = ComputeAmounts(guestsNmb, guestHotelNmb, model);

            var datas = from c in model
                        group c by c.ExpenseCategory.Name
                            into result
                            select new { Name = result.Key, Value = result.Sum(item => item.TotalAmount) };

            return Json(datas, JsonRequestBehavior.AllowGet);
        }


        public ActionResult Charts()
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            return View();
        }


        private List<Expense> ComputeAmounts(int guestsNmb, int guestHotelNmb, List<Expense> model)
        {
            foreach (var item in model)
            {
                ComputeAmount(guestsNmb, guestHotelNmb, item);
            }
            return model;
        }

        private Expense ComputeAmount(int guestsNmb, int guestHotelNmb, Expense model)
        {
            model.TotalPlanAmount = ComputePlanAmount(guestsNmb, guestHotelNmb, model);
            model.TotalAmount = !model.isFullyPaid ? model.TotalPlanAmount : model.Installments.Where(i => i.isDone).Sum(d => d.Amount);
            model.Paided = model.Installments.Where(d => d.isDone).Sum(d => d.Amount);
            model.Progress = Convert.ToDouble(model.Paided / model.TotalAmount);
            return model;
        }

        private static decimal ComputePlanAmount(int guestsNmb, int guestHotelNmb, Expense model)
        {
            decimal result;
            if (model.ExpenseType.isProPerson)
            {
                int discountedGuests = model.GuestInExpenses.Count;
                if (model.ExpenseType.isHotel)
                {
                   result = model.ActualAmount * (guestHotelNmb - discountedGuests);
                }
                else
                {
                    result = model.ActualAmount * (guestsNmb - discountedGuests);
                }
                if (discountedGuests > 0)
                {
                    var subsum = model.GuestInExpenses.Sum(subitem => model.ActualAmount*(1 - subitem.Discount));
                    result += subsum;
                }
            }
            else
            {
                result = model.ActualAmount;
            }
            return result;
        }



        //
        // GET: /Expenses/Details/5

        public ActionResult Details(int id)
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            var model = _expenseRepository.Find(id);
            if (model == null)
            {
                return HttpNotFound();
            }
            return View(model);
        }

        public ActionResult DetailsAjax(int id)
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            var model = _expenseRepository.Find(id);
            if (model == null)
            {
                return HttpNotFound();
            }
            var guests = _guestRepository.All.Where(g => g.GuestGroup.WeddingId == selectedWedding.Value).Where(g => !g.isNotIncluded);
            int guestsNmb = guests.Count();
            int guestHotelNmb = guests.Count(d => d.isHotelNeeded);
            model = ComputeAmount(guestsNmb, guestHotelNmb, model);
            return PartialView("_Details", model);
        }

        public JsonResult GetSum()
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return Json(null);
            }
            var entities = _expenseRepository.AllIncluding(expense => expense.Wedding, expense => expense.Contractor, expense => expense.ExpenseCategory, expense => expense.Tasks, expense => expense.Installments);
            entities = entities.Where(e => e.WeddingId == selectedWedding).Where(e => !e.isNotIncluded);
            var model = entities.ToList();
            var guests = _guestRepository.All.Where(g => g.GuestGroup.WeddingId == selectedWedding.Value).Where(g => !g.isNotIncluded);
            var guestsNmb = guests.Count();
            var guestHotelNmb = guests.Count(d => d.isHotelNeeded);
            model = ComputeAmounts(guestsNmb, guestHotelNmb, model);
            return Json(new
            {
                value = model.Sum(d => d.TotalAmount)
            }, JsonRequestBehavior.AllowGet);
        }

        public ActionResult GetProgress(int id)
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            var model = _expenseRepository.Find(id);
            if (model == null)
            {
                return Content("");
            }
            var guests = _guestRepository.All.Where(g => g.GuestGroup.WeddingId == selectedWedding.Value).Where(g => !g.isNotIncluded);
            int guestsNmb = guests.Count();
            int guestHotelNmb = guests.Count(d => d.isHotelNeeded);
            model = ComputeAmount(guestsNmb, guestHotelNmb, model);
            return Json(new
            {
                value = Convert.ToInt32(model.Progress * 100)
            }, JsonRequestBehavior.AllowGet);
        }

        //
        // GET: /Expenses/Create

        public ActionResult Create()
        {
            if (!SelectedWeddingId.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            ViewBag.PossibleContractors = _contractorRepository.All.OrderBy(c=>c.Name);
            ViewBag.PossibleExpenseCategories = _expensecategoryRepository.All.OrderBy(c => c.Name);
            ViewBag.PossibleExpenseTypes = _expenseTypeRepository.All.OrderBy(c => c.Name);
// ReSharper disable PossibleInvalidOperationException
            var model = new Expense {WeddingId = SelectedWeddingId.Value};
// ReSharper restore PossibleInvalidOperationException
            return View(model);
        }

        //
        // POST: /Expenses/Create

        [HttpPost]
        public ActionResult Create(Expense expense)
        {
            if (ModelState.IsValid)
            {
                _expenseRepository.InsertOrUpdate(expense);
                _expenseRepository.Save();
                return RedirectToAction("Index");
            }
            ViewBag.PossibleContractors = _contractorRepository.All.OrderBy(c => c.Name);
            ViewBag.PossibleExpenseCategories = _expensecategoryRepository.All.OrderBy(c => c.Name);
            ViewBag.PossibleExpenseTypes = _expenseTypeRepository.All.OrderBy(c => c.Name);
            return View();
        }

        //
        // GET: /Expenses/Edit/5

        public ActionResult Edit(int id)
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            var model = _expenseRepository.Find(id);
            if (model == null)
            {
                return HttpNotFound();
            }
            ViewBag.PossibleContractors = _contractorRepository.All.OrderBy(c => c.Name);
            ViewBag.PossibleExpenseCategories = _expensecategoryRepository.All.OrderBy(c => c.Name);
            ViewBag.PossibleExpenseTypes = _expenseTypeRepository.All.OrderBy(c => c.Name);
            return View(model);
        }

        //
        // POST: /Expenses/Edit/5

        [HttpPost]
        public ActionResult Edit(Expense expense)
        {
            if (ModelState.IsValid)
            {
                _expenseRepository.InsertOrUpdate(expense);
                _expenseRepository.Save();
                return RedirectToAction("Index");
            }
            ViewBag.PossibleContractors = _contractorRepository.All.OrderBy(c => c.Name);
            ViewBag.PossibleExpenseCategories = _expensecategoryRepository.All.OrderBy(c => c.Name);
            ViewBag.PossibleExpenseTypes = _expenseTypeRepository.All.OrderBy(c => c.Name);
            return View();
        }

        //
        // GET: /Expenses/Delete/5

        public ActionResult Delete(int id)
        {
            var selectedWedding = SelectedWeddingId;
            if (!selectedWedding.HasValue)
            {
                return RedirectToAction("Index", "Weddings");
            }
            var model = _expenseRepository.Find(id);
            if (model == null)
            {
                return HttpNotFound();
            }
            return View(model);
        }

        //
        // POST: /Expenses/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            _expenseRepository.Delete(id);
            _expenseRepository.Save();

            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _contractorRepository.Dispose();
                _expensecategoryRepository.Dispose();
                _expenseRepository.Dispose();
                _guestRepository.Dispose();
                _expenseTypeRepository.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

